package com.example.study.page.service

import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.app.Service
import android.content.Context
import android.content.Intent
import android.os.Binder
import android.os.Environment
import android.os.IBinder
import androidx.core.app.NotificationCompat
import com.example.study.ListActivity
import com.example.study.R
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.InputStream
import java.net.HttpURLConnection
import java.net.URL

/**
 * Created by lijinxi on 2024/2/28
 * @Description:
 */
class DownloadService : Service() {
    companion object {
        const val CHANNEL_ID = "101"
        const val CHANNEL_NAME = "下载通知"
        const val IMPORTANCE = NotificationManager.IMPORTANCE_DEFAULT
    }

    private var notificationManager: NotificationManager? = null
    private var notificationBuilder: NotificationCompat.Builder? = null
    private var downloadTask: DownloadTask? = null

    var listener: OnDownloadListener? = null

    override fun onCreate() {
        super.onCreate()
        val intent = Intent(this.applicationContext, ListActivity::class.java)
        val pendingIntent = PendingIntent.getActivity(
            this.applicationContext,
            0,
            intent,
            PendingIntent.FLAG_MUTABLE
        )
        notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        notificationManager?.createNotificationChannel(
            NotificationChannel(
                CHANNEL_ID,
                CHANNEL_NAME,
                IMPORTANCE
            )
        )
        notificationBuilder = NotificationCompat.Builder(this.applicationContext, CHANNEL_ID)
            .setContentTitle("下载中")
            .setSmallIcon(R.drawable.whale)
            .setPriority(NotificationCompat.PRIORITY_HIGH)
            .setProgress(100, 0, false)
            .setContentIntent(pendingIntent)
            .setOnlyAlertOnce(true)
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        intent?.getStringExtra("url")?.let { url ->
            //通知
            downloadTask = DownloadTask(url, object : OnDownloadListener {

                override fun onProgress(progress: Int) {
                    notificationBuilder?.setProgress(100, progress, false)
                        ?.setContentTitle("下载中: $progress%")
                    notificationManager?.notify(1, notificationBuilder?.build())
                    listener?.onProgress(progress)
                }

                override fun onSuccess(fileName: String) {
                    notificationBuilder!!.setProgress(0, 0, false)
                        .setContentTitle("下载完成")
                        .setOngoing(false)
                    notificationManager?.notify(1, notificationBuilder!!.build())
                    listener?.onSuccess(fileName)
                }

                override fun onFailed(e: Exception) {
                    notificationBuilder!!.setProgress(0, 0, false)
                        .setContentTitle("下载失败")
                        .setOngoing(false)
                    notificationManager!!.notify(1, notificationBuilder!!.build())
                    listener?.onFailed(e)
                }
            }
            )
        }
        downloadTask?.download()
        return super.onStartCommand(intent, flags, startId)
    }

    override fun onDestroy() {
        super.onDestroy()
        downloadTask?.cancel()
    }

    override fun onBind(intent: Intent?): IBinder {
        return Binder()
    }

    class DownloadTask(
        private val downloadUrl: String, private val listener: OnDownloadListener
    ) {
        companion object {
            const val TYPE_SUCCESS = 0
            const val TYPE_FAILED = 1
        }

        private lateinit var job: Job

        @OptIn(DelicateCoroutinesApi::class)
        fun download(coroutineScope: CoroutineScope? = null) {
            job = (coroutineScope ?: GlobalScope).launch {
                withContext(Dispatchers.IO) {
                    doInBackground()
                }
            }
        }

        fun cancel() {
            if (this::job.isInitialized) {
                job.cancel()
            }
        }

        private fun getFileName(downloadUrl: String): String {
            val fileName = downloadUrl.substring(downloadUrl.lastIndexOf("/"))
            val directory =
                Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
            return "$directory$fileName"
        }

        private suspend fun doInBackground(): Int {
            var inputStream: InputStream? = null
            //var outputStream: FileOutputStream? = null
            var connection: HttpURLConnection? = null

            try {
                val url = URL(downloadUrl)
                connection = withContext(Dispatchers.IO) {
                    url.openConnection()
                } as HttpURLConnection
                connection.connectTimeout = 8000
                connection.requestMethod = "GET"

                val contentLength = connection.contentLength
                inputStream = connection.inputStream
                val fileName = getFileName(downloadUrl)
                /*
                outputStream = withContext(Dispatchers.IO) {
                    FileOutputStream(fileName)
                }*/
                var total = 0L
                var len: Int
                val bytes = ByteArray(1024)
                while (withContext(Dispatchers.IO) {
                        inputStream.read(bytes)
                    }.also { len = it } != -1) {
                    /*
                    withContext(Dispatchers.IO) {
                        outputStream.write(bytes, 0, len)
                    }*/
                    total += len
                    val progress = (total * 100 / contentLength).toInt()
                    withContext(Dispatchers.Main) {
                        listener.onProgress(progress)
                    }
                }
                withContext(Dispatchers.Main) {
                    listener.onSuccess(fileName)
                }
                return TYPE_SUCCESS
            } catch (e: Exception) {
                withContext(Dispatchers.Main) {
                    listener.onFailed(e)
                }
                return TYPE_FAILED
            } finally {
                withContext(Dispatchers.IO) {
                    inputStream?.close()
                    //outputStream?.close()
                    connection?.disconnect()
                }
            }
        }

    }

    interface OnDownloadListener {
        fun onProgress(progress: Int)
        fun onSuccess(fileName: String)
        fun onFailed(e: Exception)
    }
}
